﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using MvdDonk.Bomberman.Entities;
using MvdDonk.Bomberman.Network.Messages;
using MvdDonk.Bomberman.Network.Events;
using System.Net;
using System.Net.Sockets;

namespace MvdDonk.Bomberman.Network
{
    public class Server
    {

        //public delegate void ClientConnectedEventHandler(object sender, ClientConnectedEventArgs e);
        //public event ClientConnectedEventHandler ClientConnected;

        private NetServer server;
        private string serverName;
        private double nextSendUpdates;
        private double nextSendUpdates2;

        public Server(string appIdentifier, int serverPort, string serverName)
        {
            this.serverName = serverName;
            nextSendUpdates = NetTime.Now;
            nextSendUpdates2 = NetTime.Now;

            Console.WriteLine("Initializing server");
            //Create server
            var config = new NetPeerConfiguration(appIdentifier);
            config.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
            config.Port = serverPort;

            server = new NetServer(config);
            Console.WriteLine("Starting server...");
            server.Start();
            Console.WriteLine("Server started on port: " + config.Port);
        }

        private IPEndPoint _EndPoint;
        public IPEndPoint EndPoint
        {
            get
            {
                if (_EndPoint == null)
                {
                    var host = Dns.GetHostEntry(Dns.GetHostName());
                    var localIP = IPAddress.Parse("127.0.0.1");
                    foreach (var ip in host.AddressList)
                    {
                        if (ip.AddressFamily == AddressFamily.InterNetwork)
                        {
                            localIP = ip;
                            break;
                        }
                    }

                    _EndPoint = new IPEndPoint(localIP, server.Port);
                }

                return _EndPoint;
            }
        }

        //public void StartGame()
        //{
        //    foreach (NetConnection player in server.Connections)
        //    {
        //        foreach (var otherPlayer in Bomberman.Instance.EntityManager.Players)
        //        {
        //            var om = new PositionMessage(otherPlayer.Position, otherPlayer.NetworkId);
        //            om.SendToClient(server, player);
        //        }
        //    }
        //}

        public void Shutdown()
        {
            server.Shutdown("Bye all!");
        }

        public void Poll()
        {
            NetIncomingMessage msg;
            while ((msg = server.ReadMessage()) != null)
            {
                switch (msg.MessageType)
                {
                    case NetIncomingMessageType.DiscoveryRequest:
                        Console.WriteLine("Server received a discovery request from a client; send a discovery response (with no extra data attached)");
                        var responseMsg = server.CreateMessage(serverName);
                        server.SendDiscoveryResponse(responseMsg, msg.SenderEndpoint);
                        break;
                    case NetIncomingMessageType.VerboseDebugMessage:
                    case NetIncomingMessageType.DebugMessage:
                    case NetIncomingMessageType.WarningMessage:
                    case NetIncomingMessageType.ErrorMessage:
                        //
                        // Just print diagnostic messages to console
                        //
                        Console.WriteLine(msg.ReadString());
                        break;
                    case NetIncomingMessageType.StatusChanged:
                        NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte();
                        if (status == NetConnectionStatus.Connected)
                        {
                            //
                            // A new player just connected!
                            //
                            Console.WriteLine(NetUtility.ToHexString(msg.SenderConnection.RemoteUniqueIdentifier) + " connected!");
                            Bomberman.Instance.EntityManager.AddPlayer(new Player(Bomberman.Instance.TestPlayerTexture, new Vector2(0,0), msg.SenderConnection.RemoteUniqueIdentifier, msg.SenderConnection.RemoteHailMessage.ReadString()));
                        }
                        else if (status == NetConnectionStatus.Disconnected)
                        {
                            Bomberman.Instance.EntityManager.DisconnectPlayer(msg.SenderConnection.RemoteUniqueIdentifier);
                        }
                        else
                            Console.WriteLine(status.ToString() + ": " + msg.ReadString());

                        break;
                    case NetIncomingMessageType.Data:
                        var receivedMsg = MessageFinder.GetMessageFromClient(msg);
                        if (receivedMsg is MovementMessage)
                        {
                            var castedMessage = receivedMsg as MovementMessage;
                            Bomberman.Instance.EntityManager.PlayerMovementUpdate(castedMessage);
                            Console.WriteLine(string.Format("Received movement update: [{0}, {1}]", castedMessage.MovementVector.X, castedMessage.MovementVector.Y));
                        }
                        if (receivedMsg is PositionMessage)
                        {
                            var castedMessage = receivedMsg as PositionMessage;
                            Bomberman.Instance.EntityManager.PlayerPositionUpdate(castedMessage);
                            Console.WriteLine(string.Format("Received position update: [{0}, {1}]", castedMessage.Position.X, castedMessage.Position.Y));
                        }
                        break;
                }


                //
                // send position updates 30 times per second
                //
                double now = NetTime.Now;
                if (now > nextSendUpdates)
                {
                    // Yes, it's time to send position updates

                    Console.WriteLine("Sending data to clients");
                    // for each player...
                    foreach (NetConnection player in server.Connections)
                    {
                        foreach (var otherPlayer in Bomberman.Instance.EntityManager.Players)
                        {
                            var om = new MovementMessage(otherPlayer.MovementVector, otherPlayer.MovementState, otherPlayer.NetworkId);
                            om.SendToClient(server, player);
                        }
                    }

                    // schedule next update
                    nextSendUpdates += (1.0 / 30.0);
                }


                //
                // send position updates 30 times per second
                //
                if (now > nextSendUpdates2)
                {
                    // Yes, it's time to send position updates

                    Console.WriteLine("Sending data to clients");
                    // for each player...
                    foreach (NetConnection player in server.Connections)
                    {
                        foreach (var otherPlayer in Bomberman.Instance.EntityManager.Players)
                        {
                            var om = new PositionMessage(otherPlayer.Position, otherPlayer.NetworkId);
                            om.SendToClient(server, player);
                        }
                    }

                    // schedule next update
                    nextSendUpdates2 += (1.0 / 10.0);
                }
            }
        }
    }
}
